#lang sicp
(define (deriv exp var)
  (cond ((number? exp) 0)
        ((variable? exp) (if (same-variable? exp var) 1 0))
        (else ((get (operator exp) 'deriv)
               (operands exp) var))))
(define (operator exp) (car exp))
(define (operands exp) (cdr exp))

(define get (lambda (type op) 1))
(define set (lambda (op type procedure) 1))

(define (variable? exp) (symbol? exp))
(define (same-variable? exp var) (and (variable? exp)
                                      (variable? var)
                                      (eq? exp var)))

(define (install-deriv)
  (define (make-sum a b)
    (cond ((and (number? a) (number? b))
           (+ a b))
          ((=number? a 0) b)
          ((=number? b 0) a)
          (else (list '+ a b))))
  (define (addend sum) (car sum))
  (define (augend sum) (cadr sum))

  (define deriv-to-sum (lambda (exp var)
                         (make-sum (deriv (addend exp) var)
                                   (deriv (augend exp) var))))

  (define (make-product a b)
    (cond ((or (=number? a 0) (=number? b 0)) 0)
          ((and (number? a) (number? b)) (* a b))
          ((=number? a 1) b)
          ((=number? b 1) a)
          (else (list '* a b))))
  (define (multiplier product) (car product))
  (define (multiplicand product) (cadr product))

  (define (deriv-to-product exp var)
    (make-sum (make-product
               (multiplier exp)
               (deriv (multiplicand exp) var))
              (make-product
               (deriv (multiplier exp) var)
               (multiplicand exp))))

  
  (define (make-exponentiation base exponent)
    (cond ((=number? exponent 1) base)
          ((=number? exponent 0) 1)
          (else (list '** base exponent))))
  (define (base exponentiation) (car exponentiation))
  (define (exponent exponentiation) (cadr exponentiation))
  (define (deriv-to-exponentiation exp var) 1)



  ;; install
  (set 'deriv '+ deriv-to-sum)
  (set 'deriv '* deriv-to-product)
  (set 'deriv '** deriv-to-exponentiation)
  
  'done
)



(define (=number? exp n) (and (number? exp) (number? n) (= exp n)))


(define (make-subtract a b)
  (cond ((and (number? a) (number? b)) (- a b))
        ((=number? b 0) a)
        (else (list '- a b))))
